//
//  RxSwift+Extension.swift
//  Lease_IOS
//
//  Created by Mr.wang on 2018/12/20.
//  Copyright © 2018 Mr.wang. All rights reserved.
//

import RxSwift
import SDWebImage
import RxCocoa

extension ObservableType {
    
    public func showSuccess(text: String, delay: Double = 1) -> Observable<Element> {
//        DispatchTimeInterval.seconds(<#T##Int#>)
//        return self.then { _ in
//            APPHud.shared.showSuccess(status: text, delay: delay)
//            }.delay(delay, scheduler: MainScheduler.instance)
//            .map { $0 }
        
        return self.then { _ in
            APPHud.shared.showSuccess(status: text, delay: delay)
        }.delay(DispatchTimeInterval.seconds(Int(delay)), scheduler: MainScheduler.instance)
            .map {$0}
    }
    
    public func post(_ name: Notification.Name) -> Observable<Element> {
        return self.then{ _ in
            NotificationCenter.default.post(name: name, object: nil)
        }
    }
    
    public func filterWithError(_ predicate: @escaping (Element) throws -> Bool) -> Observable<Element> {
        return filter {
            let bool = (try? predicate($0)) ?? false
            if !bool {
                throw NullError()
            }
            return bool
        }
    }
    
    public func trackingLoading(_ status: String? = nil) -> Observable<Element> {
        var hasDismissed = false
        APPHud.shared.showLoading(text: status)
        
        let dismissClosure = {
            if hasDismissed { return }
            hasDismissed = true
            APPHud.shared.dismiss()
        }
        
        return self.do(onNext: { (_) in
            dismissClosure()
        }, onError: { (_) in
            dismissClosure()
        }, onCompleted: {
            dismissClosure()
        }, onDispose: {
            dismissClosure()
        })
    }
    
    public func repeatWhen<O: ObservableType>(_ notifier: O) -> Observable<Element> {
        return notifier.map { _ in }
            .startWith(())
            .flatMap {
                self.asObservable()
        }
    }
    
    public func then(_ closure: @escaping (Element) -> ()) -> Observable<Element> {
        return map {
            closure($0)
            return $0
        }
    }
    
    public func catchErrorJustComplete() -> Observable<Element> {
        return self.catchError({ _ -> Observable<Self.Element> in
            return Observable<Self.Element>.empty()
        })
    }
    
    public func catchErrorJustReturnLast() -> Observable<Element> {
        var lastElement: Element?
        return Observable.create { observer -> Disposable in
            let disposable = self.subscribe(onNext: { (element) in
                lastElement = element
                observer.onNext(element)
            }, onError: { (error) in
                guard let element = lastElement else {
                    observer.onCompleted()
                    return
                }
                observer.onNext(element)
                observer.onCompleted()
            }, onCompleted: {
                observer.onCompleted()
            })
            return Disposables.create([disposable])
        }
    }
    
}

extension Reactive where Base: UIImageView {
    
    public var imageUrl: Binder<String> {
        return Binder(base) { imageView, imageUrl in
            if let url = URL.init(string: imageUrl) {
                imageView.sd_setImage(with: url, completed: nil)
            }
        }
    }
}

extension Reactive where Base == SDWebImageDownloader {
    
    public func downloadImage(url: String, continueInBackground: Bool = true) -> Observable<UIImage> {
        return Observable<UIImage>.create({ (observer) -> Disposable in
            guard let imageUrl = URL.init(string: url) else {
                observer.onError(NullError())
                observer.onCompleted()
                return Disposables.create()
            }
            let token = SDWebImageDownloader.shared.downloadImage(with: imageUrl, options: .continueInBackground, progress: nil) { (image, _, error, _) in
                if let error = error {
                    observer.onError(error)
                }
                if let image = image {
                    observer.onNext(image)
                }
                
                observer.onCompleted()
            }
            if continueInBackground {
                return Disposables.create()
            } else {
                return Disposables.create {
                    token?.cancel()
                }
            }
        }).subscribeOn(MainScheduler.instance)
    }
    
}

extension ObservableType where Element: Sequence {
    
    func sorted(by sort: @escaping (Element.Element, Element.Element) -> Bool) -> Observable<Element> {
        return self.map { (element) -> Element in
            let tmp = element.sorted(by: { (lhs, rhs) -> Bool in
                return sort(lhs, rhs)
            })
            if let tmpRes = tmp as? Element {
                return tmpRes
            }
            return element
        }
    }
    
}

extension BehaviorRelay {
    
    func acceptSelf() {
        self.accept(self.value)
    }
    
}
